gusucode.com > VC 电梯管理系统 > VC 电梯管理系统/gusucode/Elevator/MainDlg.cpp

    //Download by http://www.NewXing.com
// MainDlg.cpp : implementation file
//

#include "stdafx.h"
#include "Elevator.h"
#include "MainDlg.h"
#include "math.h"
#include "Splash.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/*####################################################################
  模块名称:	主控中心
  开发作者:	漫步阳光
  开发时间:	@2005.11
####################################################################*/

/////////////////////////////////////////////////////////////////////////////
// CMainDlg dialog


CMainDlg::CMainDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CMainDlg::IDD, pParent)
{
	//{{AFX_DATA_INIT(CMainDlg)
	//}}AFX_DATA_INIT
	
	try
	{
	CreateDirectory("logs",NULL);//创建存放日志的目录
	}catch(CException* e){
	AfxMessageBox("无法创建日志目录,可能是没有权限。\n\n因此本系统日志功能将失效。但不会影响系统正常运行。");
	}

	try{
	m_cLogFile.Open("logs\\log0.txt", CFile::modeCreate|CFile::modeNoTruncate|CFile::modeWrite\
		| CFile::typeText , &m_Except);//打开日志文件
	m_cLogFile.SeekToEnd();
	}catch(CException* e){}

	str_arrElevatorName[0]='A';
	str_arrElevatorName[1]='B';
	str_arrElevatorName[2]='C';
	str_arrElevatorName[3]='D';

	iTotalFailTimes = 0;

}


void CMainDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CMainDlg)
	//}}AFX_DATA_MAP
}


BEGIN_MESSAGE_MAP(CMainDlg, CDialog)
	//{{AFX_MSG_MAP(CMainDlg)
	ON_WM_DESTROY()
	ON_BN_CLICKED(IDC_BTN_ABOUT, OnBtnAbout)
	ON_WM_TIMER()
	ON_WM_CREATE()
	//}}AFX_MSG_MAP
ON_COMMAND_RANGE(IDC_FLOORBUTTONS,IDC_FLOORBUTTONS+20,OnFloorBtnClk) 
ON_MESSAGE(WM_ARRIVE_ONEFLOOR,OnOneFloorArrived)

END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CMainDlg message handlers


void CMainDlg::OnDestroy() 
{
	CDialog::OnDestroy();
	
	// TODO: Add your message handler code here
	
	for(int i=0;i<ELEVATOR_NUM;i++)
	{
		delete m_elevatorArr[i];
	}

	for(i=0;i<FLOOR_NUM;i++)
	{
		delete m_pFloorButton[i][0];
		delete m_pFloorButton[i][1];
	}

	KillTimer(1);
	lWaitQueue.~CircleSingleLink();

	try{
		Write2Log("系统成功关闭...");
		m_cLogFile.Close();
	}catch(CException* e){}


}


BOOL CMainDlg::OnInitDialog() 
{
	CDialog::OnInitDialog();

	//让窗体呆在最上层:)
	//SetWindowPos(&this->wndTopMost,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE);
	
	// TODO: Add extra initialization here
			
	//===========创建动态楼层按钮
	CString strCaption;
	int iPanelLeft = 795;
	int iPanelTop = 70;
	int iColWidth = 60;
	int iRowHeight = 60;	

	int iBtnWidth = 55;
	int iBtnHeight = 25;
	int i;

	try{

	for(i=FLOOR_NUM;i>0;i--)
	{
		strCaption.Format("%d",i);
		m_pFloorButton[i-1][0]=new CButton;
		m_pFloorButton[i-1][1]=new CButton;
		
		m_pFloorButton[i-1][0]->Create(strCaption+"↑",BS_PUSHBUTTON|WS_CHILD|WS_VISIBLE,\
			CRect(\
			iPanelLeft,\
			iPanelTop+(10-i)*iRowHeight/2,\
			iPanelLeft+iBtnWidth,\
			iPanelTop+(10-i)*iRowHeight/2+iBtnHeight),\
			this,IDC_FLOORBUTTONS+2*(i-1));//left,top,right,bottom

		m_pFloorButton[i-1][1]->Create(strCaption+"↓",BS_PUSHBUTTON|WS_CHILD|WS_VISIBLE,\
			CRect(\
			iPanelLeft+iColWidth,\
			iPanelTop+(10-i)*iRowHeight/2,\
			iPanelLeft+iColWidth+iBtnWidth,\
			iPanelTop+(10-i)*iRowHeight/2+iBtnHeight),\
			this,IDC_FLOORBUTTONS+2*(i-1)+1);//left,top,right,bottom

	}//for

	}catch(CException* e){
	AfxMessageBox("无法创建楼层按钮,程序不能正常运行。");
	return FALSE;//退出!
	}

	//隐藏掉两个无用的按钮
	m_pFloorButton[9][0]->ShowWindow(FALSE);
	m_pFloorButton[0][1]->ShowWindow(FALSE);

	try{

	for(i=0;i<ELEVATOR_NUM;i++)
	{
	m_elevatorArr[i] = new CElevatorDlg(i+1,MAX_PASSENGER_NUM,(1+i*2)%FLOOR_NUM,this);

	m_elevatorArr[i]->Create(IDD_ELEVATOR_DIALOG,this);	
	m_elevatorArr[i]->MoveWindow(CRect(i*195,0,(i+1)*195,500));
	m_elevatorArr[i]->ShowWindow(SW_SHOW);
	}

	}catch(CException* e){
	AfxMessageBox("无法创建电梯,程序不能正常运行。");
	return FALSE;//退出!
	}

	Write2Log("系统成功启动...");	
	
	return TRUE;  // return TRUE unless you set the focus to a control
	              // EXCEPTION: OCX Property Pages should return FALSE
}


/*####################################################################
// name:		OnFloorBtnClk

// input1:		UINT curBtn
				楼层按钮序号

// ouput:		void
				
// 功能描述:	响应楼层按钮的动作
// 开发作者:	漫步阳光
// 开发时间:	@2005.11
// 版本说明:	v1.0
####################################################################*/
void CMainDlg::OnFloorBtnClk(UINT curBtn) 
{
 // TODO: Add your control notification handler code here

	int iReqFloor =curBtn-1100+1;
	sOuterRequest tmpOuterRequest = No2ReqStruct(iReqFloor);

	if((lWaitQueue.searchNode(tmpOuterRequest)) > 0)
	{
		AfxMessageBox("请不要重复请求。");
		return;
	}

	/*
	//将请求加入队列
	if(!(lWaitQueue.appendTail(tmpOuterRequest)))
	{
		AfxMessageBox("无法将您的请求加入请求队列,请稍后再试。");
		return;
	}
	*/

	GetDlgItem(curBtn)->EnableWindow(FALSE);

	trytoSchedule(tmpOuterRequest);//立即尝试分派!		

}

void CMainDlg::OnCancel() 
{
	// TODO: Add extra cleanup here
	if(IDYES==MessageBox("是否真的结束?","电梯系统",MB_YESNO))		
	CDialog::OnCancel();
	
}


/*####################################################################
// name:		No2ReqStruct

// input1:		int iNo
				楼层按钮序号

// ouput:		sOuterRequest
				该按钮对应的楼层和方向结构体

// 功能描述:	将楼层按钮序号转换成对应的楼层和方向
// 开发作者:	漫步阳光
// 开发时间:	@2005.11
// 版本说明:	v1.0
####################################################################*/
sOuterRequest CMainDlg::No2ReqStruct(int iNo)
{
sOuterRequest tempVal;
if(iNo%2==0) 
{
	tempVal.eReqDirection =DOWN;
}
else
{
	tempVal.eReqDirection =UP;
	iNo++;
}

tempVal.iReqFloor = iNo/2;
tempVal.iAge =0;
tempVal.bReClaimed = FALSE;
return tempVal;
}


int CMainDlg::ReqStruct2No(const sOuterRequest& tmpRequest)
{
return (tmpRequest.eReqDirection==UP) ? (2*(tmpRequest.iReqFloor-1)) : (2*(tmpRequest.iReqFloor-1)+1);

}

/*####################################################################
// name:		Goodness

// input1:		sOuterRequest tmpOuterRequest
				用户请求结构体

// ouput:		int
				找到的最佳接收电梯(优先数最小的)的ID

// 功能描述:	为用户请求寻找一个最佳接收电梯 
// 开发作者:	漫步阳光
// 开发时间:	@2005.11
// 版本说明:	v1.0
####################################################################*/
int CMainDlg::Goodness(const sOuterRequest& tmpOuterRequest)
{
int returnVal = -1;

//挨个查看各正常电梯的状态
int tmpCurFloor;
int tmpCurWeight;
int tmpPrioValue;
bool tmpCanSchedule;
enum state tmpState;

int iPrioValue = 10000;//优先数,优先数越小优先级越大
for(int i=0;i<ELEVATOR_NUM; i++)
{
	tmpState = m_elevatorArr[i]->getState();
	tmpCurFloor = m_elevatorArr[i]->getCurFloor();
	tmpCurWeight = m_elevatorArr[i]->getCurWeight();
	tmpCanSchedule = m_elevatorArr[i]->canSchedule();

if(tmpState!=MAL_FUNCTION && tmpCanSchedule)
{
	if(tmpState==IDLE || \
		(tmpOuterRequest.eReqDirection==UP && (tmpState==UP_RUN || tmpState==UP_PAUSE)) || \
		(tmpOuterRequest.eReqDirection==DOWN && (tmpState==DOWN_RUN || tmpState==DOWN_PAUSE)) )
	{
		if(tmpState==IDLE)
		{
			//计算该电梯的优先数
			tmpPrioValue = DIST_PRIO*abs(tmpOuterRequest.iReqFloor-tmpCurFloor)+\
				WEIGHT_PRIO*tmpCurWeight;

		if(tmpPrioValue<iPrioValue)
		{
			iPrioValue = tmpPrioValue;
			returnVal = i;
		}
		}

		if(tmpOuterRequest.eReqDirection==UP && tmpOuterRequest.iReqFloor>=tmpCurFloor)
		{
			//计算该电梯的优先数
			tmpPrioValue = DIST_PRIO*(tmpOuterRequest.iReqFloor-tmpCurFloor)+\
				WEIGHT_PRIO*tmpCurWeight;

		if(tmpPrioValue<iPrioValue)
		{
			iPrioValue = tmpPrioValue;
			returnVal = i;
		}
		}

		if(tmpOuterRequest.eReqDirection==DOWN && tmpOuterRequest.iReqFloor<=tmpCurFloor)
		{
			//计算该电梯的优先数
			tmpPrioValue = DIST_PRIO*(tmpCurFloor-tmpOuterRequest.iReqFloor)+\
				WEIGHT_PRIO*tmpCurWeight;

		if(tmpPrioValue<iPrioValue)
		{
			iPrioValue = tmpPrioValue;
			returnVal = i;
		}
		}

	}
}
}//for

return returnVal;

}


/*####################################################################
// name:		Schedule

// input1:		
				
// ouput:		void
				
// 功能描述:	定时处理主控中心请求队列中请求
// 开发作者:	漫步阳光
// 开发时间:	@2005.11
// 版本说明:	v1.0
// 行为说明:
 该函数被周期性激活,以定时分发请求队列中的请求
 该函数在队列空时停止定时器并直接返回,否则
 对于当前等待队列中的每个请求尝试分发::
 将成功分发出去的请求删除,未成功分发的做好标记并增加年龄后重新放回队列
 对于年龄大于一定值(也就是超过一定时间仍未得到分派)的请求则直接删除

####################################################################*/
void CMainDlg::Schedule()
{

if(lWaitQueue.getLength() == 0)
{
KillTimer(1);//队列空了,歇会
return;
}

int iReqFloor;
CString tempString,tempString1;
sOuterRequest tmpOuterRequest;

while(lWaitQueue.cutHead(tmpOuterRequest) && !tmpOuterRequest.bReClaimed)
{

	if(tmpOuterRequest.iAge < BAD_REQUEST_AGE)//如果此请求长时间没有得到分配,则直接删除
	{
	trytoSchedule(tmpOuterRequest);
	}
	else//对于长时间不能调度出去的请求也要处理一下后事:(
	{
		iReqFloor = ReqStruct2No(tmpOuterRequest);//转换成请求按钮号
		GetDlgItem(IDC_FLOORBUTTONS+iReqFloor)->EnableWindow(TRUE);
		iTotalFailTimes++;//递增总调度失败次数
		tempString.Format("%d",tmpOuterRequest.iReqFloor);	
		tempString1 = (tmpOuterRequest.eReqDirection==UP) ? "↑":"↓";		
		AfxMessageBox("很抱歉,下面的请求因超时而被系统取消,请重新请求。\r\n"+tempString+tempString1);
	}

}

//将本次追加到队尾的请求标识位恢复
if(tmpOuterRequest.bReClaimed){
tmpOuterRequest.bReClaimed = FALSE;
lWaitQueue.appendTail(tmpOuterRequest);
}

lWaitQueue.refreshLink();

}



void CMainDlg::trytoSchedule(sOuterRequest& tmpRequest)
{

int targetElevator=-1,iReqFloor;
CString tempString,tempString1;

	if((targetElevator = Goodness(tmpRequest))<0)//目前没有找到合适的接受者,再放入
	{
		tmpRequest.iAge++;
		tmpRequest.bReClaimed = TRUE;
		lWaitQueue.appendTail(tmpRequest);
	}
	else //发消息给目标电梯
	{

	//对于电梯刚好在当前楼层的情况,电梯的返回往往比下面的程序段还要快!
	//所以此段程序不能跟下面的那行调换位置!!!
	tempString1.Format("%c",str_arrElevatorName[targetElevator]);	
	iReqFloor = ReqStruct2No(tmpRequest);//转换成请求按钮号
	GetDlgItem(IDC_FLOORBUTTONS+iReqFloor)->GetWindowText(tempString);	
	GetDlgItem(IDC_FLOORBUTTONS+iReqFloor)->SetWindowText(tempString+"("+tempString1+")");

	m_elevatorArr[targetElevator]->acceptReq(tmpRequest);
	}

		KillTimer(1);
		SetTimer(1,SCHEDULE_INTERVAL*1000,NULL);//启动主控中心调度定时器
}


void CMainDlg::OnBtnAbout() 
{
	::AfxMessageBox("关于本电梯系统", MB_USERDEFINE);

}

void CMainDlg::OnTimer(UINT nIDEvent) 
{
	// TODO: Add your message handler code here and/or call default
	switch(nIDEvent)
	{
	case 1:
	Schedule();
		break;
	}
	
	CDialog::OnTimer(nIDEvent);
}


LONG CMainDlg::OnOneFloorArrived(WPARAM wP,LPARAM lP)
{

	int iReqFloor=(int)wP;
	CString tempString;

	GetDlgItem(IDC_FLOORBUTTONS+iReqFloor)->EnableWindow(TRUE);
	GetDlgItem(IDC_FLOORBUTTONS+iReqFloor)->GetWindowText(tempString);

	if(tempString.GetLength() >4 )
	{
	tempString = tempString.Mid(0,tempString.GetLength()-3);
	GetDlgItem(IDC_FLOORBUTTONS+iReqFloor)->SetWindowText(tempString);
	}

	//Invalidate(); //重画窗体
	return 0;
}


void CMainDlg::Write2Log(const CString& content) 
{
	// TODO: Add your control notification handler code here

	if(content=="") return;

CTime m_SysTime = CTime::GetCurrentTime();

try{
m_cLogFile.WriteString(content+"\t("+m_SysTime.Format("%Y-%m-%d %H:%M:%S")+")\n");
}catch(CException* e){}

}

int CMainDlg::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
	if (CDialog::OnCreate(lpCreateStruct) == -1)
		return -1;
	
	// TODO: Add your specialized creation code here
	CSplashWnd::ShowSplashScreen(this); //显示启动画面


	return 0;
}